package dilema_do_prisioneiro;

import java.util.Arrays;

/**
 *
 * @author Guilherme
 */
public class IndividuoDP implements Comparable {

    private boolean[] cromossomo;
    private double fitness;
    private int tipo_individuo;
    private int tipo_fitness;
    private boolean mod;
    private DilemaPrisioneiro dp;

    public IndividuoDP(DilemaPrisioneiro dp, boolean[] cromossomo, int tipo_ind, int tipo_fit) {
        this.dp = dp;
        this.cromossomo = cromossomo;
        this.tipo_individuo = tipo_ind;
        this.tipo_fitness = tipo_fit;
        mod = true;
    }

    public IndividuoDP(IndividuoDP ind) {
        this.dp = ind.getDp();
        this.cromossomo = Arrays.copyOf(ind.getCromossomo(), ind.getCromossomo().length);
        this.tipo_individuo = new Integer(ind.getTipo());
        this.fitness = new Double(ind.getFitness());
        this.mod = new Boolean(ind.isMod());
    }

    public boolean[] getCromossomo() {
        return cromossomo;
    }

    public DilemaPrisioneiro getDp() {
        return dp;
    }

    public double getFitness() {
        if (mod) {
            this.calcularFitness();
        }
        return fitness;
    }

    public void calcularFitness() {
        fitness = 0.0;
        if (tipo_individuo == 0) {
            this.compararESomarFitness();
        } else if (tipo_individuo == 1) {
            for (int i = 0; i < dp.getTamanhoPopulacao() / 2.0; i++) {
                this.compararESomarFitness();
            }
            fitness /= (dp.getTamanhoPopulacao() / 2.0);//Média
        } else if (tipo_individuo == 2) {
            for (int i = 0; i < dp.getTamanhoPopulacao(); i++) {
                this.compararESomarFitness();
            }
            fitness /= dp.getTamanhoPopulacao();//Média
        }
        mod = false;
        fitness = (-1*fitness + this.getBonus());
    }
    
    private void compararESomarFitness(){
        if (tipo_fitness == 0) {
            fitness += this.compararIndividuo(dp.getIndividuoAleatorioDiferenteDe(this));
        } else {
            fitness += this.compararGrupo(dp.getIndividuoAleatorioDiferenteDe(this));
        }        
    }

    private double compararIndividuo(IndividuoDP ind) {
        double meses_de_cadeia = 0.0;
        for (int i = 0; i < cromossomo.length; i++, meses_de_cadeia++) {
            if (this.getGene(i) == true & ind.getGene(i) == false) {
                meses_de_cadeia += 360; //30 anos
            } else if (this.getGene(i) == true & ind.getGene(i) == true) {
                meses_de_cadeia += 6;   //6 meses
            } else if (this.getGene(i) == false & ind.getGene(i) == false) {
                meses_de_cadeia += 120; //10 anos
            } else if (this.getGene(i) == false & ind.getGene(i) == true) {
                meses_de_cadeia += 0;   //1 dia
            }
        }
        return meses_de_cadeia / cromossomo.length;
    }

    private double compararGrupo(IndividuoDP ind) {
        double meses_de_cadeia = 0.0;
        for (int i = 0; i < cromossomo.length; i++, meses_de_cadeia++) {
            if (this.getGene(i) == true & ind.getGene(i) == false) {
                meses_de_cadeia += 360; //30 anos + 0 anos
            } else if (this.getGene(i) == true & ind.getGene(i) == true) {
                meses_de_cadeia += 12;  //6 meses + 6 meses
            } else if (this.getGene(i) == false & ind.getGene(i) == false) {
                meses_de_cadeia += 240; //10 anos + 10 anos
            }
        }
        return meses_de_cadeia / cromossomo.length;
    }

    private double getBonus() {
        double cont_bonus = 0;
        for (int i = 0, cadeia = 0; i < cromossomo.length; i++) {
            if (this.getGene(i) == true) {
                cadeia++;
            } else {
                cadeia = 0;
            }
            if (cadeia == 3) {
                cadeia = 0;
                cont_bonus++;
            }
        }
        return 20 * cont_bonus;
    }

    public void setGene(int x, boolean bool) {
        this.cromossomo[x] = bool;
        mod = true;
    }

    public boolean getGene(int x) {
        return this.cromossomo[x];
    }

    public int getTipo() {
        return tipo_individuo;
    }

    public boolean isMod() {
        return mod;
    }

    @Override
    public int compareTo(Object o) {
        Double fit1 = this.getFitness();
        Double fit2 = ((IndividuoDP) o).getFitness();
        return fit1.compareTo(fit2);
    }

}
